﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;

using Microsoft.Dss.ServiceModel.DsspServiceBase;
using W3C.Soap;
using submgr = Microsoft.Dss.Services.SubscriptionManager;

using Microsoft.Ccr.Adapters.WinForms;
using Microsoft.Dss.Services.Directory;
//using Microsoft.Robotics.RoboChamps.Sensors.GPS.Proxy;
using Microsoft.Dss.ServiceModel.Dssp;
//using webcam = Microsoft.Robotics.Services.WebCam.Proxy;

using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;

using webcam = Microsoft.Robotics.Services.WebCam.Proxy;

//using urban = Microsoft.Robotics.Services.UrbanDashboard.Proxy;

namespace AI
{
    [Contract(Contract.Identifier)]
    [DisplayName("AI")]
    [Description("AI service (no description provided)")]
    public class AIService : DsspServiceBase
    {

        public const string API_KEY = "ABCDE12345";


        webcam.WebCamOperations _webcamPort = null;
        //webcam.WebCamOperations webcamPort2 = null;

        webcam.WebCamOperations _webcamSubscribePort = null;

        //webcam.WebCamOperations webcamPort = null;
        //webcam.WebCamOperations webcamPort2 = null;

        //webcam.WebCamOperations webcamSubscribePort = null;


        /// <summary>
        /// Service state
        /// </summary>
        [ServiceState]
        AIState _state = new AIState();

        /// <summary>
        /// Main service port
        /// </summary>
        [ServicePort("/AI", AllowMultipleInstances = true)]
        AIOperations _mainPort = new AIOperations();


        //[SubscriptionManagerPartner]
        //submgr.SubscriptionManagerPort _submgrPort2 = new submgr.SubscriptionManagerPort();
        
        [Partner("SubMgr", Contract = submgr.Contract.Identifier, CreationPolicy = PartnerCreationPolicy.CreateAlways)]
        private submgr.SubscriptionManagerPort _subMgrPort = new submgr.SubscriptionManagerPort();



        //[Partner("Dashboard", Contract = urban.Contract.Identifier, CreationPolicy = PartnerCreationPolicy.UsePartnerListEntry)]
        //urban.UrbanDashboardOperations _urbanDashboardPort = new urban.UrbanDashboardOperations();

        /// <summary>
        /// Service constructor
        /// </summary>
        public AIService(DsspServiceCreationPort creationPort)
            : base(creationPort)
        {

        }

        /// <summary>
        /// Service start
        /// </summary>
        protected override void Start()
        {
            base.Start();

            SpawnIterator(DoStart);

            // 
            // Add service specific initialization here
            
            Activate(Arbiter.Interleave(
                new TeardownReceiverGroup
                (
                    //Arbiter.Receive<DsspDefaultDrop>(false, _mainPort, DropHandler)
                ),
                new ExclusiveReceiverGroup
                (
                    Arbiter.ReceiveWithIterator<Connect>(true, _mainPort, ConnectHandler)
                    
                ),
                new ConcurrentReceiverGroup
                (
                    
                    //Arbiter.ReceiveWithIterator<DestInfoUpdate>(true, _mainPort, DestInfoUpdateHandler),
                                        Arbiter.ReceiveWithIterator<UrbanSignal>(true, _mainPort, NotifySignalHandler),
                    Arbiter.ReceiveWithIterator<GpsUpdate>(true, _mainPort, GpsUpdateHandler),

                    Arbiter.ReceiveWithIterator<LRFUpdate>(true, _mainPort, LRFUpdateHandler),

                    Arbiter.ReceiveWithIterator<NotifyDrive>(true, _mainPort, NotifyDriveHandler),

                    Arbiter.ReceiveWithIterator<TargetInfo>(true, _mainPort, TargetInfoHandler),

                    Arbiter.ReceiveWithIterator<Subscribe>(true, _mainPort, SubscribeHandler),
                    Arbiter.ReceiveWithIterator<EventCamUpdate>(true, _mainPort, EventCamUpdateHandler)
                    
                )
            ));

            //DirectoryInsert();

            WinFormsServicePort.Post(new RunForm(CreateAppForm));			

        }



        private IEnumerator<ITask> DoStart()
        {
            // Send API Key
            //yield return Arbiter.Choice(
            //    _urbanDashboardPort.SetAPIKey(new urban.SetAPIKeyRequest(API_KEY)),
            //    delegate(DefaultUpdateResponseType respone) { LogInfo("API KEY set"); },
            //    delegate(Fault f) { LogError(f); });



            // Start the car
            //yield return Arbiter.Choice(
            //    _genericDifferentialDrivePort.EnableDrive(true),
            //    delegate(DefaultUpdateResponseType respone) { },
            //    delegate(Fault f) { LogError(f); });

            //yield return Arbiter.Choice(
            //    _genericDifferentialDrivePort.SetDrivePower(0.5d, 0.5d),
            //    delegate(DefaultUpdateResponseType respone) { },
            //    delegate(Fault f) { LogError(f); });

            yield break;
        }


        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        public virtual IEnumerator<ITask> ConnectHandler(Connect update)
        {

            _webcamPort = ServiceForwarder<webcam.WebCamOperations>("/" + "Camera2");
            //webcamPort2 = ServiceForwarder<webcam.WebCamOperations>("/" + "Camera2");


            _webcamSubscribePort = new webcam.WebCamOperations();
            //webcamSubscribePort2 = new webcam.WebCamOperations();



            //yield return Arbiter.Choice<SubscribeResponseType, W3C.Soap.Fault>(
            //    _webcamPort.Subscribe(_webcamSubscribePort),
            //    delegate(SubscribeResponseType response)
            //    {
            //        Activate(Arbiter.ReceiveWithIterator<webcam.UpdateFrame>(false, _webcamSubscribePort, updateFrameHandler));

            //        WinFormsServicePort.Post(new FormInvoke(delegate()
            //        {
            //            try
            //            {
            //                //_form.label1.Text = camUrl;
            //            }
            //            catch (Exception ex)
            //            {
            //                LogInfo(ex.ToString());
            //                Console.WriteLine(ex);
            //            }
            //        }));
            //    },
            //    delegate(W3C.Soap.Fault fault)
            //    {
            //        Console.WriteLine("CAM Failed to Subscribe " + fault.ToException());
            //    });

            update.ResponsePort.Post(DefaultUpdateResponseType.Instance);
            yield break;
        }




        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public IEnumerator<ITask> SubscribeHandler(Subscribe subscribe)
        {
            SubscribeHelper(_subMgrPort, subscribe.Body, subscribe.ResponsePort);
            yield break;
        }


        AIInfo _form;

        AIInfo CreateAppForm()
        {
            _form = new AIInfo(_mainPort);
            return _form;
        }

        /// <summary>
        /// Handles Subscribe messages
        /// </summary>
        /// <param name="subscribe">the subscribe request</param>
        //[ServiceHandler]
        //public void SubscribeHandler(Subscribe subscribe)
        //{
        //    SubscribeHelper(_submgrPort, subscribe.Body, subscribe.ResponsePort);
        //}
        
        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public virtual IEnumerator<ITask> LRFUpdateHandler(LRFUpdate update)
        {

            
            WinFormsServicePort.Post(new FormInvoke(delegate()
            {
                try
                {
                    _form._ObstacleAngle = update.Body._Angle;
                }
                catch (Exception ex)
                {
                    LogInfo(ex.ToString());
                    Console.WriteLine(ex);
                }
            }));
            yield break;

        }




        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public virtual IEnumerator<ITask> GpsUpdateHandler(GpsUpdate update)
        {
            WinFormsServicePort.Post(new FormInvoke(delegate()
            {
                try
                {
                    _form.SetCurrentPos2(update.Body.CurrentLongitude, update.Body.CurrentLatitude, update.Body.XDiff, update.Body.YDiff);
                }
                catch (Exception ex)
                {
                    LogInfo(ex.ToString());
                    Console.WriteLine(ex);
                }
            }));

            yield break;
        }

        //[ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        //public virtual IEnumerator<ITask> DestInfoUpdateHandler(DestInfoUpdate update)
        //{


        //    WinFormsServicePort.Post(new FormInvoke(delegate()
        //    {
        //        try
        //        {

        //            _form.SetDestPos(update.Body);
        //        }
        //        catch (Exception ex)
        //        {
        //            LogInfo(ex.ToString());
        //            Console.WriteLine(ex);
        //        }
        //    }));
        //    yield break;
        //}


        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public virtual IEnumerator<ITask> NotifySignalHandler(UrbanSignal update)
        {

            //_form.labelRSignal.Text = update.Body.Signal;

            WinFormsServicePort.Post(new FormInvoke(delegate()
            {
                try
                {
                    //_form.AddLog("dfs");

                    _form.SetRGCount(update.Body);
                }
                catch (Exception ex)
                {
                    LogInfo(ex.ToString());
                    Console.WriteLine(ex);
                }
            }));

            yield break;
        }

        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public virtual IEnumerator<ITask> EventCamUpdateHandler(EventCamUpdate update)
        {

            SendNotification<EventCamUpdate>(_subMgrPort, update.Body);

            yield break;
        }

        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public virtual IEnumerator<ITask> NotifyDriveHandler(NotifyDrive update)
        {

            SendNotification<NotifyDrive>(_subMgrPort, update.Body);

            yield break;
        }

        [ServiceHandler(ServiceHandlerBehavior.Concurrent)]
        public virtual IEnumerator<ITask> TargetInfoHandler(TargetInfo update)
        {
            



            //WinFormsServicePort.Post(new FormInvoke(delegate()
            //{
            //    try
            //    {

            //        _form.SetTargetPos(-update.Body.TargetLongitude, update.Body.TargetLatitude);
            //    }
            //    catch (Exception ex)
            //    {
            //        LogInfo(ex.ToString());
            //        Console.WriteLine(ex);
            //    }
            //}));
            yield break;

        }

        


    }
}


